package com.ssy.lingxi.purchase.serviceimpl.noline;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.DateUtil;
import com.ssy.lingxi.component.rabbitMQ.constants.MessageConstants;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.member.merchant.api.feign.inner.MemberDetailFeign;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberFeignSubordinateMemberVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.MemberManageQueryVO;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.constant.WsAction;
import com.ssy.lingxi.message.api.feign.SystemMessageControllerFeign;
import com.ssy.lingxi.message.api.feign.WsMessageControllerFeign;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.message.api.vo.request.WsMessageRequest;
import com.ssy.lingxi.purchase.api.common.OrderConstant;
import com.ssy.lingxi.purchase.api.common.PurchaseInquiryConstant;
import com.ssy.lingxi.purchase.api.dto.request.BaseDetailsRequest;
import com.ssy.lingxi.purchase.api.dto.request.bidding.BiddingListRequest;
import com.ssy.lingxi.purchase.api.dto.request.bidding.BiddingProductRequest;
import com.ssy.lingxi.purchase.api.dto.request.online.OnlineProductRequest;
import com.ssy.lingxi.purchase.api.dto.request.online.OnlineSignUpRequest;
import com.ssy.lingxi.purchase.api.dto.request.online.SubmitReportPriceRequest;
import com.ssy.lingxi.purchase.api.dto.response.BiddingExternalWorkStateEnumResponse;
import com.ssy.lingxi.purchase.api.dto.response.CountryAreaResponse;
import com.ssy.lingxi.purchase.api.dto.response.bidding.*;
import com.ssy.lingxi.purchase.api.dto.response.online.OfferLogsResponse;
import com.ssy.lingxi.purchase.api.dto.response.online.OnlineBiddingDetailsResponse;
import com.ssy.lingxi.purchase.api.dto.response.online.QuotationDeskResponse;
import com.ssy.lingxi.purchase.api.enums.bidding.*;
import com.ssy.lingxi.purchase.api.enums.common.CommonBooleanEnum;
import com.ssy.lingxi.purchase.api.enums.onlinebidding.*;
import com.ssy.lingxi.purchase.api.enums.purchase.StatusEnum;
import com.ssy.lingxi.purchase.api.dto.response.online.CountryArea;
import com.ssy.lingxi.purchase.config.rabbitmq.OrderRbbitMqRequest;
import com.ssy.lingxi.purchase.entity.bidding.*;
import com.ssy.lingxi.purchase.entity.onlinebidding.*;
import com.ssy.lingxi.purchase.model.enums.ExternalLogTypeEnum;
import com.ssy.lingxi.purchase.repository.bidding.BiddingProductRepository;
import com.ssy.lingxi.purchase.repository.bidding.BiddingRepository;
import com.ssy.lingxi.purchase.repository.online.OnLineBiddingProductRepository;
import com.ssy.lingxi.purchase.repository.online.OnLineBiddingRepository;
import com.ssy.lingxi.purchase.repository.online.OnlineInteriorLogRepository;
import com.ssy.lingxi.purchase.repository.online.OnlineMaterielRepository;
import com.ssy.lingxi.purchase.service.online.OnlineBiddinService;
import com.ssy.lingxi.purchase.serviceimpl.BaseBiddingService;
import com.ssy.lingxi.workflow.api.model.contant.ProcessEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 在线竞价
 */
@Slf4j
@Service
public class OnlineBiddinServiceImpl extends BaseBiddingService implements OnlineBiddinService {

    private static ObjectMapper mapper = new ObjectMapper();
    @Resource
    BiddingRepository biddingRepository;
    @Resource
    OnLineBiddingRepository onlineBiddingRepository;
    @Resource
    OnlineMaterielRepository onlineMaterielRepository;
    @Resource
    OnlineInteriorLogRepository onlineInteriorLogRepository;
    @Resource
    OnLineBiddingProductRepository onLineBiddingProductRepository;
    @Resource
    IRedisStringUtils redisStringUtils;
    @Resource
    BiddingProductRepository biddingProductRepository;
    @Resource
    WsMessageControllerFeign wsMessageControllerFeign;
    @Resource
    SystemMessageControllerFeign systemMessageControllerFeign;
    @Resource
    MemberDetailFeign memberDetailFeign;

    /**
     * 创建线程池
     */
    private static ExecutorService executor = new ThreadPoolExecutor(8, 16,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(1024),
            new BasicThreadFactory.Builder().namingPattern("purchase-bidding-%d").daemon(true).build(),
            new ThreadPoolExecutor.AbortPolicy());

    /**
     * 采购竞价单查询
     */
    @Override
    public Wrapper<PageData<BiddingListResponse>> biddingList(BiddingListRequest request, UserLoginCacheDTO sysUser) {
        Specification<Bidding> biddingQuery = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            //在线竞价实体
            Join<Object, Object> onLineJoin = root.join("onLineBidding", JoinType.LEFT);
            //竞价会员
            Join<Object, Object> memberJoin = onLineJoin.join("materiels", JoinType.LEFT);

            //会员名称
            if (StringUtils.hasLength(request.getMemberName()))
                predicates.add(criteriaBuilder.like(root.get("createMemberName"), "%" + request.getMemberName() + "%"));
            //竞价单创建时间
            if (null != request.getStartTime()) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), request.getStartTime()));
            }
            if (null != request.getEndTime()) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), request.getEndTime()));
            }
            //报名时间
            if (null != request.getSignupStartTime()) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("startSignUp"), request.getSignupStartTime()));
            }
            if (null != request.getSignupEndTime()) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("endSignUp"), request.getSignupEndTime()));
            }
            //摘要
            if (StringUtils.hasLength(request.getDetails())) {
                predicates.add(criteriaBuilder.like(root.get("details"), "%" + request.getDetails() + "%"));
            }
            //竞价单号
            if (StringUtils.hasLength(request.getBiddingNo())) {
                predicates.add(criteriaBuilder.like(root.get("biddingNo"), "%" + request.getBiddingNo() + "%"));
            }

            //外部状态
            Integer externalState = request.getExternalState();
            List<Integer> exCodes = OnlineBiddingExternalWorkStateEnum.getCodes();
            if (Objects.nonNull(externalState)){
                predicates.add(criteriaBuilder.equal(memberJoin.get("externalState"), externalState));
            }else {
                predicates.add(criteriaBuilder.in(memberJoin.get("externalState")).value(exCodes));
            }

            //内部状态
            Integer interiorState = request.getInteriorState();
            List<Integer> inCodes = OnlineInteriorWorkStateEnum.getCodes();
            if (Objects.nonNull(interiorState)){
                predicates.add(criteriaBuilder.equal(memberJoin.get("interiorState"), interiorState));
            }else {
                predicates.add(criteriaBuilder.in(memberJoin.get("interiorState")).value(inCodes));
            }
            //报名信息要和登录信息匹配
            predicates.add(criteriaBuilder.equal(memberJoin.get("createMemberId"), sysUser.getMemberId()));
            predicates.add(criteriaBuilder.equal(memberJoin.get("createMemberRoleId"), sysUser.getMemberRoleId()));

            Predicate[] predicate = new Predicate[predicates.size()];
            return criteriaBuilder.and(predicates.toArray(predicate));
        };
        Page<Bidding> biddings = biddingRepository.findAll(biddingQuery, PageRequest.of(request.getCurrent(), request.getPageSize(), Sort.by("biddingStartTime").descending()));
        List<Bidding> content = biddings.getContent();
        if (CollectionUtils.isEmpty(content)){
            return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
        }
        long totalElements = content.size();
        content = content.stream().distinct().filter(bidding -> Objects.nonNull(bidding.getOnLineBidding())).collect(Collectors.toList());
        //竞价会员信息为空, 内外部状态取在线竞价主表状态, 否则取竞价会员的个人内外部状态
        List<BiddingListResponse> responses = new ArrayList<>();
        content.forEach(bidding -> {
            BiddingListResponse response = BeanUtil.copyProperties(bidding, BiddingListResponse.class);
            OnLineBidding onLineBidding = bidding.getOnLineBidding();
            OnlineMateriel materiel = onLineBidding.getMateriels().stream().filter(onlineMateriel -> sysUser.getMemberId().equals(onlineMateriel.getCreateMemberId()) &&
                    sysUser.getMemberRoleId().equals(onlineMateriel.getCreateMemberRoleId())).findFirst().orElse(null);
            if (Objects.isNull(materiel)){
                return;
            }else {
                response.setExternalState(materiel.getExternalState());
                response.setInteriorState(materiel.getInteriorState());
                //如果状态为已完成 , 则显示是否中标
                if (OnlineBiddingExternalWorkStateEnum.COMPLETE.getState().equals(onLineBidding.getExternalState())){
                    response.setIsPrize(materiel.getIsPrize());
                }
            }
            //竞价单为发布至采购门户, 则会员不能为待竞价报名
            if (PurchaseInquiryConstant.type.PLATFORM.equals(bidding.getType()) && StatusEnum.NO.getState().equals(materiel.getIsSignUp())) {
                return;
            }
            response.setExternalStateName(OnlineBiddingExternalWorkStateEnum.getName(response.getExternalState()));
            response.setInteriorStateName(OnlineInteriorWorkStateEnum.getName(response.getInteriorState()));
            responses.add(response);
        });

        //数据补偿
        if (totalElements > 0 && totalElements == request.getPageSize() && responses.size() < totalElements){
            Page<Bidding> compensates = biddingRepository.findAll(biddingQuery, PageRequest.of(request.getCurrent() + 1, request.getPageSize(), Sort.by("biddingStartTime").descending()));
            List<Bidding> data = compensates.getContent();
            if (!CollectionUtils.isEmpty(data)){
                data = data.stream().distinct().filter(bidding -> {
                    OnLineBidding onLineBidding = bidding.getOnLineBidding();
                    OnlineMateriel materiel = onLineBidding.getMateriels().stream().filter(onlineMateriel -> sysUser.getMemberId().equals(onlineMateriel.getCreateMemberId()) &&
                            sysUser.getMemberRoleId().equals(onlineMateriel.getCreateMemberRoleId())).findFirst().orElse(null);
                    if (Objects.isNull(materiel)){
                        return false;
                    }
                    //竞价单为发布至采购门户, 则会员需要为已竞价报名
                    if (PurchaseInquiryConstant.type.PLATFORM.equals(bidding.getType()) && StatusEnum.NO.getState().equals(materiel.getIsSignUp())) {
                        return false;
                    }
                    return Objects.nonNull(bidding.getOnLineBidding());
                }).collect(Collectors.toList());
                long division;
                if (data.size() + responses.size() > totalElements){
                    division = totalElements - responses.size();
                    data = data.subList(0, (int) division);
                }
                //竞价会员信息为空, 内外部状态取在线竞价主表状态, 否则取竞价会员的个人内外部状态
                data.forEach(bidding -> {
                    BiddingListResponse response = BeanUtil.copyProperties(bidding, BiddingListResponse.class);
                    OnLineBidding onLineBidding = bidding.getOnLineBidding();
                    OnlineMateriel materiel = onLineBidding.getMateriels().stream().filter(onlineMateriel -> sysUser.getMemberId().equals(onlineMateriel.getCreateMemberId()) &&
                            sysUser.getMemberRoleId().equals(onlineMateriel.getCreateMemberRoleId())).findFirst().orElse(null);
                    if (Objects.isNull(materiel)){
                        return;
                    }else {
                        response.setExternalState(materiel.getExternalState());
                        response.setInteriorState(materiel.getInteriorState());
                        //如果状态为已完成 , 则显示是否中标
                        if (OnlineBiddingExternalWorkStateEnum.COMPLETE.getState().equals(onLineBidding.getExternalState())){
                            response.setIsPrize(materiel.getIsPrize());
                        }
                    }
                    response.setExternalStateName(OnlineBiddingExternalWorkStateEnum.getName(response.getExternalState()));
                    response.setInteriorStateName(OnlineInteriorWorkStateEnum.getName(response.getInteriorState()));
                    responses.add(response);
                });
            }
        }

        return Wrapper.success(new PageData<>(biddings.getTotalElements(), responses));
    }

    /**
     * 采购竞价单详情
     */
    @Override
    public Wrapper<OnLineBiddingDetailsResponse> biddingDetails(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        OnLineBiddingDetailsResponse response = new OnLineBiddingDetailsResponse();
        Bidding bidding;
        if (null != request.getId()) {
            bidding = biddingRepository.findById(request.getId()).orElse(null);
        } else {
            bidding = biddingRepository.findByBiddingNo(request.getNumber());
        }
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        } //查询当前报价详情
        OnLineBidding onLineBidding = bidding.getOnLineBidding();
        if (Objects.isNull(onLineBidding)){
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        //采购商不能对自己的竞价单进行操作
        if (bidding.getCreateMemberId().equals(sysUser.getMemberId()) && bidding.getCreateMemberRoleId().equals(sysUser.getMemberRoleId())){
            throw new BusinessException(ResponseCode.NOT_ELIGIBLE_FOR_BIDDING);
        }

        //查询当前报价会员信息
        OnlineMateriel materiel = onlineMaterielRepository.findByOnlineBiddingAndCreateMemberIdAndCreateMemberRoleId(onLineBidding, sysUser.getMemberId(), sysUser.getMemberRoleId());
        //内外部状态换成供应商个人状态
        BeanUtils.copyProperties(bidding, response);
        response.setInteriorState(materiel.getInteriorState());
        response.setInteriorStateName(OnlineInteriorWorkStateEnum.getName(materiel.getInteriorState()));
        response.setExternalState(materiel.getExternalState());
        response.setExternalStateName(OnlineBiddingExternalWorkStateEnum.getName(materiel.getExternalState()));
        //适用区域
        response.setAreas(bidding.getAreas().stream().map(temp -> BeanUtil.copyProperties(temp, CountryAreaResponse.class)).collect(Collectors.toList()));
        Long id = bidding.getId();
        //查询采购竞价单物料信息列表
        response.setMateriels(getMateriels(id));
        //查询采购竞价单外部流程记录
        response.setExternalLogs(getSupplyExternalLog(id, sysUser.getMemberId(), sysUser.getMemberRoleId()));
        //查询采购竞价单外部流程状态图
        response.setExternalLogStates(getLogStateExternal(ProcessEnum.PURCHASE_BIDDING_EXTERNAL.getCode(), bidding.getExternalNextStep(),bidding.getOnLineBidding().getMemberRoleId(),bidding.getCreateMemberRoleId()));
        //组装截止时间给前端
        response.setDays(0<= DateUtil.judgeTime(response.getBiddingEndTime())[0]?DateUtil.judgeTime(response.getBiddingEndTime())[0]:0);
        response.setHours(0<=DateUtil.judgeTime(response.getBiddingEndTime())[1]?DateUtil.judgeTime(response.getBiddingEndTime())[1]:0);
        response.setMinutes(0<=DateUtil.judgeTime(response.getBiddingEndTime())[2]?DateUtil.judgeTime(response.getBiddingEndTime())[2]:0);
        //报价会员信息
        Long memberId = sysUser.getMemberId();
        Long memberRoleId = sysUser.getMemberRoleId();
        //授标结果
        response.setAwardsFruit(getAwardsFruits(id));
        //授标人信息
        Long biddingMemberId = onLineBidding.getMemberId();
        Long biddingMemberRoleId = onLineBidding.getMemberRoleId();
        if (biddingMemberId != null && biddingMemberId > 0 && biddingMemberRoleId != null && biddingMemberRoleId >0) {
            OnlineMateriel onlineMateriel = onLineBidding.getMateriels().stream().filter(temp -> biddingMemberId.equals(temp.getCreateMemberId()) && biddingMemberRoleId.equals(temp.getCreateMemberRoleId())).findFirst().orElse(null);
            if (StatusEnum.YES.getState().equals(materiel.getIsOffer()) && Objects.nonNull(onlineMateriel) && !CollectionUtils.isEmpty(onlineMateriel.getProducts())){
                //最低报价记录
                List<AwardProcessDetailsResponse> process = onlineMateriel.getProducts().stream().filter(product -> onlineMateriel.getPeportPriceSum().equals(product.getReportNumber())).map(temp -> BeanUtil.copyProperties(temp, AwardProcessDetailsResponse.class)).collect(Collectors.toList());
                response.setAwardProcess(process);
                //当前用户最低价报价总额
                double sum = process.stream().mapToDouble(AwardProcessDetailsResponse::getPrice).sum();
                response.setReportPrice(sum);
                //是否中标
                Integer isPrize = memberId.equals(biddingMemberId) && memberRoleId.equals(biddingMemberRoleId)? CommonBooleanEnum.YES.getCode() : CommonBooleanEnum.NO.getCode();
                response.setIsPrize(isPrize);
//                Long ranking = redisStringUtils.findZSet(PurchaseInquiryConstant.BIDDING_RANKING_LIST_KEY + onLineBidding.getId(), memberId + "_" + memberRoleId);
                response.setRanking(process.get(0).getRanking());
            }
        }
        response.setOnlineId(onLineBidding.getId());
        response.setReturnUrls(onLineBidding.getReturnUrls());
        response.setAwardResults(onLineBidding.getAwardResults());
        response.setContent(onLineBidding.getContent());
        response.setSumAwardPrice(onLineBidding.getSumAwardPrice());
        response.setIsTargetPrice(bidding.getIsTargetPrice());
        response.setTargetPrice(bidding.getTargetPrice());
        response.setIsOpenPurchase(bidding.getIsOpenPurchase());
        response.setIsOpenRanking(bidding.getIsOpenRanking());
        response.setSignUpAreas(materiel.getSignUpAreas());
        response.setSignUpIdea(onLineBidding.getSignUpIdea());
        return Wrapper.success(response);
    }

    /**
     * 采购物料分页查询
     */
    @Override
    public Wrapper<PageData<BiddingProductRequest>> materielPage(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        Bidding bidding;
        if (null != request.getId()) {
            bidding = biddingRepository.findById(request.getId()).orElse(null);
        } else {
            bidding = biddingRepository.findByBiddingNo(request.getNumber());
        }
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        Long id = bidding.getId();
        Page<BiddingProduct> biddingProducts = biddingProductRepository.findAllByBiddingId(id, PageRequest.of(request.getCurrent(), request.getPageSize(), Sort.by("id").ascending()));
        long count = biddingProducts.getTotalElements();
        if (0 == count) {
            return Wrapper.success(new PageData<>(count, new ArrayList<>()));
        }
        List<BiddingProductRequest> collect = biddingProducts.getContent().stream().map(temp -> {
            BiddingProductRequest response = new BiddingProductRequest();
            BeanUtils.copyProperties(temp, response);
            response.setItemNo(temp.getItemNo());
            return response;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(biddingProducts.getTotalElements(), collect));
    }

    /**
     * 最低竞价信息
     */
    @Override
    public Wrapper<PageData<AwardProcessDetailsResponse>> minimumBidding(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        //查询当前报价详情
        OnLineBidding onLineBidding = onlineBiddingRepository.findFirstByBiddingId(request.getId());
        if (ObjectUtils.isEmpty(onLineBidding)) {
            return Wrapper.success(new PageData<>(0L, null));
        }
        OnlineMateriel onlineMateriel = onlineMaterielRepository.findByOnlineBiddingAndCreateMemberIdAndCreateMemberRoleIdAndIsOffer(onLineBidding, sysUser.getMemberId(), sysUser.getMemberRoleId(), StatusEnum.YES.getState());
        if (Objects.isNull(onlineMateriel)){
            return Wrapper.success(new PageData<>(0L, null));
        }
        Page<OnLineBiddingProduct> productPage = onLineBiddingProductRepository.findAllByOnlineMaterielAndReportNumber(onlineMateriel, onlineMateriel.getPeportPriceSum(), PageRequest.of(request.getCurrent(), request.getPageSize()));
        List<AwardProcessDetailsResponse> awardsFruitsResponses;
        if (0 < productPage.getTotalPages()) {
            awardsFruitsResponses = productPage.get().map(temp -> {
                AwardProcessDetailsResponse response = new AwardProcessDetailsResponse();
                BeanUtils.copyProperties(temp, response);
                response.setUnitPrice(temp.getUnitPrice());
                return response;
            }).collect(Collectors.toList());
            return Wrapper.success(new PageData<>(productPage.getTotalElements(), awardsFruitsResponses));
        }
        return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
    }

    /**
     * 采购竞价单详情-授标结果 使用竞价单ID查询
     */
    @Override
    public Wrapper<PageData<AwardProcessDetailsResponse>> awardResultsBidding(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        Bidding bidding;
        if (null != request.getId()) {
            bidding = biddingRepository.findById(request.getId()).orElse(null);
        } else {
            bidding = biddingRepository.findByBiddingNo(request.getNumber());
        }
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        //查询中标报价详情
        OnLineBidding onLineBidding = onlineBiddingRepository.findFirstByBiddingId(bidding.getId());
        if (ObjectUtils.isEmpty(onLineBidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        //授标会员信息
        OnlineMateriel onlineMateriel = onlineMaterielRepository.findByOnlineBiddingAndCreateMemberIdAndCreateMemberRoleIdAndIsSignUp(onLineBidding, onLineBidding.getMemberId(), onLineBidding.getMemberRoleId(), StatusEnum.YES.getState());
        if(Objects.isNull(onlineMateriel)){
            return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
        }
        Page<OnLineBiddingProduct> productPage = onLineBiddingProductRepository.findAllByOnlineMaterielAndReportNumber(onlineMateriel, onlineMateriel.getPeportPriceSum(), PageRequest.of(request.getCurrent(), request.getPageSize()));
        List<AwardProcessDetailsResponse> awardsFruitsResponses;
        if (0 < productPage.getTotalPages()) {
            awardsFruitsResponses = productPage.get().map(temp -> {
                AwardProcessDetailsResponse response = new AwardProcessDetailsResponse();
                BeanUtils.copyProperties(temp, response);
                response.setUnitPrice(temp.getUnitPrice());
                return response;
            }).collect(Collectors.toList());
            return Wrapper.success(new PageData<>(productPage.getTotalElements(), awardsFruitsResponses));
        }
        return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
    }

    /**
     * 采购竞价单详情-查询竞价过程
     */
    @Override
    public Wrapper<List<AwardProcessResponse>> process(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        List<AwardProcessResponse> awardProces;
        try {
            awardProces = getAwardProces(request.getId(), sysUser);
        } catch (JsonProcessingException e) {
            log.error("查询物料资料- 转化供应商报价信息异常");
            return Wrapper.fail(ResponseCode.GET_INFORMATION_EXCEPTION);
        }
        return Wrapper.success(awardProces);
    }

    /**
     * 待竞价报名列表
     */
    @Override
    public Wrapper<PageData<BiddingListResponse>> stayExamineBiddingSignup(BiddingListRequest request, UserLoginCacheDTO sysUser) {
        long time = System.currentTimeMillis();
        Specification<Bidding> biddingQuery = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            //在线竞价实体
            Join<Object, Object> onLineJoin = root.join("onLineBidding", JoinType.LEFT);
            //竞价会员
            Join<Object, Object> memberJoin = onLineJoin.join("materiels", JoinType.LEFT);

            //会员名称
            if (StringUtils.hasLength(request.getMemberName()))
                predicates.add(criteriaBuilder.like(root.get("createMemberName"), "%" + request.getMemberName() + "%"));
            //竞价单创建时间
            if (null != request.getStartTime()) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), request.getStartTime()));
            }
            if (null != request.getEndTime()) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), request.getEndTime()));
            }
            //报名时间
            if (null != request.getSignupStartTime()) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("startSignUp"), request.getSignupStartTime()));
            }
            if (null != request.getSignupEndTime()) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("endSignUp"), request.getSignupEndTime()));
            }
            //摘要
            if (StringUtils.hasLength(request.getDetails())) {
                predicates.add(criteriaBuilder.like(root.get("details"), "%" + request.getDetails() + "%"));
            }
            //竞价单号
            if (StringUtils.hasLength(request.getBiddingNo())) {
                predicates.add(criteriaBuilder.like(root.get("biddingNo"), "%" + request.getBiddingNo() + "%"));
            }

            //报名截止时间不能小于当前时间
            predicates.add(criteriaBuilder.gt(root.get("endSignUp"), time));
            //外部状态
            predicates.add(criteriaBuilder.or(
                    criteriaBuilder.equal(memberJoin.get("externalState"), OnlineBiddingExternalWorkStateEnum.STAY_SIGNUP_BIDDING.getState()),
                    criteriaBuilder.equal(memberJoin.get("externalState"), OnlineBiddingExternalWorkStateEnum.SIGNUP_BIDDING_NOT.getState())
            ));
            //报名信息要和登录信息匹配
            predicates.add(criteriaBuilder.equal(memberJoin.get("createMemberId"), sysUser.getMemberId()));
            predicates.add(criteriaBuilder.equal(memberJoin.get("createMemberRoleId"), sysUser.getMemberRoleId()));

            Predicate[] predicate = new Predicate[predicates.size()];
            return criteriaBuilder.and(predicates.toArray(predicate));
        };
        Page<Bidding> biddings = biddingRepository.findAll(biddingQuery, PageRequest.of(request.getCurrent(), request.getPageSize(), Sort.by("startSignUp").descending()));
        List<Bidding> content = biddings.getContent();
        if (CollectionUtils.isEmpty(content)){
            return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
        }
        //未报名时 竞价会员信息为空, 内外部状态取在线竞价主表状态, 否则取竞价会员的个人内外部部状态
        List<BiddingListResponse> responses = new ArrayList<>();
        content.stream().distinct().forEach(bidding -> {
            BiddingListResponse response = BeanUtil.copyProperties(bidding, BiddingListResponse.class);
            OnLineBidding onLineBidding = bidding.getOnLineBidding();
            OnlineMateriel materiel = onLineBidding.getMateriels().stream().filter(onlineMateriel -> sysUser.getMemberId().equals(onlineMateriel.getCreateMemberId()) &&
                    sysUser.getMemberRoleId().equals(onlineMateriel.getCreateMemberRoleId())).findFirst().orElse(null);
            if (Objects.isNull(materiel)) {
                return;
            }
            //数据权限
            //竞价单为发布至采购门户, 则需要会员内部状态为已竞价报名
            if (PurchaseInquiryConstant.type.PLATFORM.equals(bidding.getType()) && !OnlineInteriorWorkStateEnum.BIDDING_HAS_BEEN_SIGNED_UP.getState().equals(materiel.getInteriorState())) {
                return;
            }
            if (time >= bidding.getStartSignUp()){
                response.setButtons(OnlineAudteExternalStateEnum.SIGNUP_BIDDING_NOT.getState().equals(materiel.getExternalAdutState()) ? Collections.singletonList(BiddingButtonEnums.RE_SIGN_UP.getState()) : Collections.singletonList(BiddingButtonEnums.SIGN_UP.getState()));
            }
            response.setExternalState(materiel.getExternalState());
            response.setInteriorState(materiel.getInteriorState());

            //内外部状态
            response.setExternalStateName(OnlineBiddingExternalWorkStateEnum.getName(response.getExternalState()));
            response.setInteriorStateName(OnlineInteriorWorkStateEnum.getName(response.getInteriorState()));
            responses.add(response);
        });

        return Wrapper.success(new PageData<>(biddings.getTotalElements(), responses));
    }

    /**
     * 创建在线竞价实体 - 采购商提交采购竞价单后
     * @param id 采购竞价单id
     * @param biddingNo 采购竞价单编号
     * @param externalState 采购竞价单外部状态
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public OnLineBidding createOnlineBidding(Long id, String biddingNo, Integer externalState) {
        OnLineBidding onLineBidding = onlineBiddingRepository.findFirstByBiddingId(id);
        if (Objects.nonNull(onLineBidding)){
            throw new BusinessException(ResponseCode.PURCHASE_DATA_RECORDS_DON_T_EXIST);
        }
        Bidding bidding = biddingRepository.findById(id).orElse(null);
        if (Objects.isNull(bidding)){
            throw new BusinessException(ResponseCode.PURCHASE_DATA_RECORDS_DON_T_EXIST);
        }
        onLineBidding = new OnLineBidding();
        onLineBidding.setBidding(bidding);
        onLineBidding.setBiddingNo(biddingNo);
        onLineBidding.setExternalState(externalState);
        onLineBidding.setCreateTime(System.currentTimeMillis());
        onLineBidding.setUpdateTime(System.currentTimeMillis());
        //状态为待竞价报名
        onLineBidding.setInteriorState(OnlineInteriorWorkStateEnum.TO_BE_APPROVED_BY_BIDDING.getState());
        onlineBiddingRepository.saveAndFlush(onLineBidding);
        //创建会员竞价信息实体 , 如果是发布至平台则为该采购商所有下级会员创建竞价信息
        List<OnlineMateriel> materiels = new ArrayList<>();
        if (StatusEnum.YES.getState().equals(bidding.getType())) {
            //查询下级会员信息
            MemberFeignSubordinateMemberVO memberVO = new MemberFeignSubordinateMemberVO();
            memberVO.setMemberId(bidding.getCreateMemberId());
            memberVO.setMemberRoleId(bidding.getCreateMemberRoleId());
            Wrapper<List<MemberManageQueryVO>> result = memberDetailFeign.subordinateMemberList(memberVO);
            if (ResponseCode.SUCCESS.getCode() != result.getCode() || CollectionUtils.isEmpty(result.getData())){
                throw new BusinessException(ResponseCode.NO_SUBORDINATE_INFORMATION_FOUND);
            }
            List<MemberManageQueryVO> manageQueryVOS = result.getData();
            for (MemberManageQueryVO member : manageQueryVOS) {
                OnlineMateriel materiel = new OnlineMateriel();
                materiel.setCreateMemberId(member.getMemberId());
                materiel.setCreateMemberName(member.getName());
                materiel.setCreateMemberRoleId(member.getRoleId());
                //内外部状态为待报名
                materiel.setInteriorState(OnlineInteriorWorkStateEnum.TO_BE_APPROVED_BY_BIDDING.getState());
                materiel.setExternalState(OnlineBiddingExternalWorkStateEnum.STAY_SIGNUP_BIDDING.getState());
                materiel.setOnlineBidding(onLineBidding);
                materiel.setIsSignUp(StatusEnum.NO.getState());
                materiels.add(materiel);
            }
        }else{
            //会员竞价报名信息, 未报名状态
            List<BiddingDemandMember> members = bidding.getMembers();
            for (BiddingDemandMember member : members) {
                OnlineMateriel materiel = new OnlineMateriel();
                materiel.setCreateMemberId(member.getMemberId());
                materiel.setCreateMemberName(member.getMemberName());
                materiel.setCreateMemberRoleId(member.getRoleId());
                //内外部状态为待报名
                materiel.setInteriorState(OnlineInteriorWorkStateEnum.TO_BE_APPROVED_BY_BIDDING.getState());
                materiel.setExternalState(OnlineBiddingExternalWorkStateEnum.STAY_SIGNUP_BIDDING.getState());
                materiel.setOnlineBidding(onLineBidding);
                materiel.setIsSignUp(StatusEnum.NO.getState());
                materiels.add(materiel);
            }
        }
        onlineMaterielRepository.saveAll(materiels);
        return onLineBidding;
    }

    /**
     * 竞价报名
     */
    @Transactional
    @Override
    public Wrapper<Void> onlineSignUp(OnlineSignUpRequest request, UserLoginCacheDTO sysUser) {
        Bidding bidding = biddingRepository.findById(request.getBiddingId()).orElse(null);
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        //当前竞价报名未到开始时间
        if (bidding.getStartSignUp() >= System.currentTimeMillis()) {
            return Wrapper.fail(ResponseCode.SIGNUP_TIME_NOT);
        }
        //当前竞价报名已经结束
        if (bidding.getEndSignUp() <= System.currentTimeMillis()) {
            return Wrapper.fail(ResponseCode.REGISTRATION_IS_OVER);
        }
        //邀请人信息 判断是否有报名资格
        Long memberId = sysUser.getMemberId();
        Long memberRoleId = sysUser.getMemberRoleId();
        List<BiddingDemandMember> members = bidding.getMembers();
        if (!CollectionUtils.isEmpty(members) && members.stream().allMatch(member -> !memberId.equals(member.getMemberId()) && !memberRoleId.equals(member.getRoleId()))){
            return Wrapper.fail(ResponseCode.NOT_ELIGIBLE_FOR_REGISTRATION);
        }
        //判断状态是否为重新报名还是第一次报名
        OnLineBidding onLineBidding = onlineBiddingRepository.findFirstByBiddingId(request.getBiddingId());
        if (Objects.isNull(onLineBidding)) {
            return Wrapper.fail(ResponseCode.EXCEL_UPLOAD_ERROR_NULL);
        }
        OnlineMateriel onlineMateriel = onlineMaterielRepository.findByOnlineBiddingAndCreateMemberIdAndCreateMemberRoleId(bidding.getOnLineBidding(), memberId, memberRoleId);
        if (Objects.isNull(onlineMateriel)){
            return Wrapper.fail(ResponseCode.NOT_ELIGIBLE_FOR_REGISTRATION);
        }
        //内部流转操作
        Integer state;
        //未报名
        if (StatusEnum.NO.getState().equals(onlineMateriel.getIsSignUp())){
            //内外部状态为 待竞价报名
            if (!OnlineInteriorWorkStateEnum.TO_BE_APPROVED_BY_BIDDING.getState().equals(onlineMateriel.getInteriorState()) &&
                !OnlineBiddingExternalWorkStateEnum.STAY_SIGNUP_BIDDING.getState().equals(onlineMateriel.getExternalState())){
                return Wrapper.fail(ResponseCode.QUOTED_PRICE_STATE_NOT);
            }
            onlineMateriel.setIsSignUp(StatusEnum.YES.getState());
            state = BiddingOperationStateEnum.BIDDING_ONLINE.getState();
        }else {
            //重新报名
            //外部状态为竞价报名审核不通过 内部状态为已竞价报名
            if (!OnlineInteriorWorkStateEnum.BIDDING_HAS_BEEN_SIGNED_UP.getState().equals(onlineMateriel.getInteriorState()) &&
                    !OnlineBiddingExternalWorkStateEnum.SIGNUP_BIDDING_NOT.getState().equals(onlineMateriel.getExternalState())){
                return Wrapper.fail(ResponseCode.QUOTED_PRICE_STATE_NOT);
            }
            state = BiddingOperationStateEnum.BIDDING_HAS_RE_SIGNED_UP.getState();
        }
        //组装数据
        assemblyData(request, onlineMateriel);
        //个人外部状态为待审核竞价报名 内部状态为已竞价报名
        onlineMateriel.setExternalState(OnlineBiddingExternalWorkStateEnum.STAY_EXAMINE_SIGNUP_BIDDING.getState());
        onlineMateriel.setInteriorState(OnlineInteriorWorkStateEnum.BIDDING_HAS_BEEN_SIGNED_UP.getState());
        //个人审核外部状态为待审核竞价报名 内部审核状态为待审核竞价报名
        onlineMateriel.setInteriorAdutState(OnlineAudteInteriorStateEnum.TO_BE_SIGNUP_APPROVED_BY_BIDDING.getState());
        onlineMateriel.setExternalAdutState(OnlineAudteExternalStateEnum.STAY_EXAMINE_SIGNUP_BIDDING.getState());

        onlineMaterielRepository.saveAndFlush(onlineMateriel);

        if (CollectionUtils.isEmpty(onLineBidding.getMateriels())){
            onLineBidding.setMateriels(Collections.singletonList(onlineMateriel));
        }

        onLineBidding.setUpdateTime(System.currentTimeMillis());
        onlineBiddingRepository.saveAndFlush(onLineBidding);
        //记录内部操作记录
        initOnlineInteriorLog(sysUser, state, OnlineInteriorWorkStateEnum.WAITING_FOR_BIDDING.getState(),onLineBidding.getId(), "");
        //外部操作记录
        saveExternalLog(sysUser, BiddingOperationStateEnum.BIDDING_ONLINE.getState(), OnlineBiddingExternalWorkStateEnum.STAY_EXAMINE_SIGNUP_BIDDING.getState(), bidding.getId(), ExternalLogTypeEnum.BIDDING_REGISTRATION.getCode(), "", sysUser.getMemberId(), sysUser.getMemberRoleId());
        //发送采购商发送审核竞价报名系统消息
        sendSystemMessageBidding(bidding, MessageTemplateCode.purchase_bidding_audit_register);
        return Wrapper.success();
    }

    /**
     * 发送采购商发送审核竞价报名系统消息
     */
    @Async
    public void sendSystemMessageBidding(Bidding bidding, String name) {
        try {
            SystemMessageRequest request = new SystemMessageRequest();
            request.setMemberId(bidding.getCreateMemberId());
            request.setRoleId(bidding.getCreateMemberRoleId());
            request.setMessageNotice(name);
            request.setParams(Arrays.asList(bidding.getBiddingNo(), bidding.getDetails(), BiddingOperationStateEnum.AUDIT_BIDDING_ONLINE.getCHName()));
            systemMessageControllerFeign.sendSystemMessage(request);
        } catch (Exception e) {
            log.error("发送竞价单通知消息异常", e);
        }
    }

    /**
     * 待竞价列表
     */
    @Override
    public Wrapper<PageData<BiddingListResponse>> stayBiddingList(BiddingListRequest request, UserLoginCacheDTO sysUser) {
        long time = System.currentTimeMillis();
        Specification<Bidding> biddingQuery = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            //在线竞价实体
            Join<Object, Object> onLineJoin = root.join("onLineBidding", JoinType.LEFT);
            //竞价会员
            Join<Object, Object> memberJoin = onLineJoin.join("materiels", JoinType.LEFT);

            //会员名称
            if (StringUtils.hasLength(request.getMemberName()))
                predicates.add(criteriaBuilder.like(root.get("createMemberName"), "%" + request.getMemberName() + "%"));
            //竞价单创建时间
            if (null != request.getStartTime()) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), request.getStartTime()));
            }
            if (null != request.getEndTime()) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), request.getEndTime()));
            }
            //报名时间
            if (null != request.getSignupStartTime()) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("startSignUp"), request.getSignupStartTime()));
            }
            if (null != request.getSignupEndTime()) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("endSignUp"), request.getSignupEndTime()));
            }
            //摘要
            if (StringUtils.hasLength(request.getDetails())) {
                predicates.add(criteriaBuilder.like(root.get("details"), "%" + request.getDetails() + "%"));
            }
            //竞价单号
            if (StringUtils.hasLength(request.getBiddingNo())) {
                predicates.add(criteriaBuilder.like(root.get("biddingNo"), "%" + request.getBiddingNo() + "%"));
            }

            //竞价截止时间大于当前时间
            predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("biddingEndTime"), System.currentTimeMillis()));
            //在线竞价单外部状态为待竞价
            predicates.add(criteriaBuilder.equal(root.get("externalState"), OnlineBiddingExternalWorkStateEnum.STAY_BIDDING.getState()));
            //内部状态为待竞价
            predicates.add(criteriaBuilder.equal(memberJoin.get("interiorState"), OnlineInteriorWorkStateEnum.WAITING_FOR_BIDDING.getState()));
            //报名信息要和登录信息匹配
            predicates.add(criteriaBuilder.equal(memberJoin.get("createMemberId"), sysUser.getMemberId()));
            predicates.add(criteriaBuilder.equal(memberJoin.get("createMemberRoleId"), sysUser.getMemberRoleId()));
            //会员需要已经竞价报名 并且报名审核通过
            predicates.add(criteriaBuilder.equal(memberJoin.get("isSignUp"), StatusEnum.YES.getState()));
            predicates.add(criteriaBuilder.equal(memberJoin.get("externalAdutState"), OnlineAudteExternalStateEnum.SIGNUP_BIDDING_PASS.getState()));

            Predicate[] predicate = new Predicate[predicates.size()];
            return criteriaBuilder.and(predicates.toArray(predicate));
        };
        Page<Bidding> biddings = biddingRepository.findAll(biddingQuery, PageRequest.of(request.getCurrent(), request.getPageSize(), Sort.by("biddingStartTime").descending()));
        List<Bidding> content = biddings.getContent();
        if (CollectionUtils.isEmpty(content)){
            return Wrapper.success(new PageData<>(0L, new ArrayList<>()));
        }
        //内外部状态取在线竞价主表状态
        List<BiddingListResponse> responses = content.stream().distinct().map(bidding -> {
            BiddingListResponse response = BeanUtil.copyProperties(bidding, BiddingListResponse.class);
            OnLineBidding onLineBidding = bidding.getOnLineBidding();
            response.setOnlineBiddingId(onLineBidding.getId());
            response.setExternalStateName(OnlineBiddingExternalWorkStateEnum.getName(response.getExternalState()));
            response.setInteriorStateName(OnlineBiddingExternalWorkStateEnum.getName(response.getExternalState()));
            if (time >= bidding.getBiddingStartTime()) {
                response.setButtons(Collections.singletonList(BiddingButtonEnums.START_BIDDING.getState()));
            }
            return response;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(biddings.getTotalElements(), responses));
    }

    /**
     * 待竞价详情
     */
    @Override
    public Wrapper<OnlineBiddingDetailsResponse> stayBiddingDetails(BaseDetailsRequest request, UserLoginCacheDTO sysUser) {
        OnlineBiddingDetailsResponse response = new OnlineBiddingDetailsResponse();
        Bidding bidding = biddingRepository.findById(request.getId()).orElse(null);
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        //查询当前报价详情
        OnLineBidding onLineBidding = onlineBiddingRepository.findFirstByBiddingId(bidding.getId());
        if (ObjectUtils.isEmpty(onLineBidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        //竞价是否开始
        if (bidding.getBiddingStartTime() > System.currentTimeMillis()){
            return Wrapper.fail(ResponseCode.BIDDING_NOT_STARTED);
        }
        //竞价是否结束
        if (bidding.getBiddingEndTime() < System.currentTimeMillis()){
            return Wrapper.fail(ResponseCode.THE_BIDDING_HAS_ENDED);
        }
        //查询竞价信息
        OnlineMateriel onlineMateriel = onlineMaterielRepository.findByOnlineBiddingAndCreateMemberIdAndCreateMemberRoleIdAndIsSignUp(onLineBidding, sysUser.getMemberId(), sysUser.getMemberRoleId(), StatusEnum.YES.getState());
        if (Objects.isNull(onlineMateriel)){
            return Wrapper.fail(ResponseCode.NOT_BIDDING_REGISTRATION);
        }
        BeanUtils.copyProperties(bidding, response);
        response.setId(onLineBidding.getId());
        response.setBiddingId(bidding.getId());
        //查询采购竞价单外部流程状态图
        response.setExternalLogStates(getLogStateExternal(ProcessEnum.PURCHASE_BIDDING_EXTERNAL.getCode(), bidding.getExternalNextStep(),bidding.getOnLineBidding().getMemberRoleId(),bidding.getCreateMemberRoleId()));
        //竞价物料查询
        response.setMateriels(getMateriels(bidding.getId()));
        //是否有竞价记录
        if (StatusEnum.NO.getState().equals(onlineMateriel.getIsOffer())){
            return Wrapper.success(response);
        }
        //报价历史
        List<OfferLogsResponse> offerLogsResponses;
        try {
            offerLogsResponses = offerLogs(response, onLineBidding, sysUser.getMemberId(), sysUser.getMemberRoleId(), onlineMateriel.getPeportPriceSum());
        } catch (JsonProcessingException e) {
            log.error("报价历史- 转化供应商报价信息异常");
            return Wrapper.fail(ResponseCode.GET_INFORMATION_EXCEPTION);
        }
        //查询物料资料(竞价过程)
        List<AwardProcessResponse> awardProces;
        try {
            awardProces = getAwardProces(bidding.getId(), sysUser);
        } catch (JsonProcessingException e) {
            log.error("查询物料资料- 转化供应商报价信息异常");
            return Wrapper.fail(ResponseCode.GET_INFORMATION_EXCEPTION);
        }
        response.setAwardProcess(awardProces);
        //组装报价台信息
        List<QuotationDeskResponse> quotationDeskResponses = quotationDesks(offerLogsResponses);
        if (!CollectionUtils.isEmpty(quotationDeskResponses)) {
            response.setQuotationDesks(quotationDeskResponses);
            //获取当前最低价格的报价单
//            Map<String, Double> typedTuples = redisStringUtils.rangeWithScores(PurchaseInquiryConstant.BIDDING_RANKING_LIST_KEY + request.getId(), 0, 0);
            //获取排名
//            response.setRanking(redisStringUtils.findZSet(PurchaseInquiryConstant.BIDDING_RANKING_LIST_KEY + request.getId(), onLineBidding.getId() + "") + 1);
        }
        return Wrapper.success(response);
    }

    /**
     * 竞价-提交报价
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> submitReportPrice(SubmitReportPriceRequest request, UserLoginCacheDTO sysUser) {
        Bidding bidding = biddingRepository.findById(request.getBiddingId()).orElse(null);
        if (ObjectUtils.isEmpty(bidding)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        //判断时间段是否正确
        long time = System.currentTimeMillis();
        if (bidding.getBiddingEndTime() < time) {
            return Wrapper.fail(ResponseCode.THE_BIDDING_HAS_ENDED);
        }
        if (bidding.getBiddingStartTime() > time) {
            return Wrapper.fail(ResponseCode.BIDDING_NOT_STARTED);
        }
        OnLineBidding onLineBidding = onlineBiddingRepository.findById(request.getOnlineId()).orElse(null);
        //会员报价信息
        OnlineMateriel onlineMateriel = onlineMaterielRepository.findByOnlineBiddingAndCreateMemberIdAndCreateMemberRoleIdAndIsSignUp(onLineBidding, sysUser.getMemberId(), sysUser.getMemberRoleId(), StatusEnum.YES.getState());
        if (ObjectUtils.isEmpty(onLineBidding) || ObjectUtils.isEmpty(onlineMateriel)) {
            return Wrapper.fail(ResponseCode.RECORDS_DON_T_EXIST);
        }
        //计算报价总金额
        Double sumPricie = request.getMateriels().stream().mapToDouble(OnlineProductRequest::getPrice).sum();
        //获取当前最低价
        Double minPrice = getMinPrice(onLineBidding, sumPricie);
        //当前最低价-报价金额(含税)是否大于或等于最小价差
        //判断条件
        long peportPriceSum = onlineMateriel.getPeportPriceSum() == null? 1 : onlineMateriel.getPeportPriceSum() + 1;
        Wrapper<Void> reportPrice = isReportPrice(bidding, onLineBidding, sumPricie, minPrice, peportPriceSum);
        if (reportPrice.getCode() != ResponseCode.SUCCESS.getCode()) {
            return reportPrice;
        }
        //更新缓存竞价单总报价次数、最低报价金额、报价会员信息
        onlineMateriel.setPeportPriceSum(peportPriceSum);
        onLineBidding.setCount(onLineBidding.getCount() + 1);

        //更报价排名信息到缓存
        updateRanking(onLineBidding, onlineMateriel, sumPricie, minPrice, sysUser.getCompany());
        //修改或者添加保存报价物料信息
        initOnlineMateriels(onlineMateriel, request.getMateriels(), onLineBidding, minPrice);
        bidding.setUpdateTime(time);
        onLineBidding.setUpdateTime(time);
        onlineMateriel.setIsOffer(StatusEnum.YES.getState());
        onlineMateriel.setSumPrice(sumPricie);
        onlineMateriel.setReportTime(time);
        //个人外部状态和内部状态保持不动 , 等竞价时间截止变为 待确认竞价结果和已竞价
//        onlineMateriel.setExternalState(OnlineBiddingExternalWorkStateEnum.BIDDING_CONFIRM_RETURN.getState());
//        onlineMateriel.setInteriorState(OnlineInteriorWorkStateEnum.ALREADY_BIDDING.getState());
        biddingRepository.saveAndFlush(bidding);
        onlineBiddingRepository.saveAndFlush(onLineBidding);
        onlineMaterielRepository.saveAndFlush(onlineMateriel);
        onlineMaterielRepository.flush();
        //保存内部流转记录
        initOnlineInteriorLog(sysUser, BiddingOperationStateEnum.BIDDING.getState(), OnlineInteriorWorkStateEnum.ALREADY_BIDDING.getState(), onLineBidding.getId(), "");
        //保存外部流转记录
        saveExternalLog(sysUser, BiddingOperationStateEnum.BIDDING.getState(), OnlineBiddingExternalWorkStateEnum.BIDDING_CONFIRM_RETURN.getState(), bidding.getId(), ExternalLogTypeEnum.BIDDING.getCode(), "", sysUser.getMemberId(), sysUser.getMemberRoleId());
        //把竞价变动实时反馈给前端
        sendWebSocket(bidding);
        //同时计算其他供应商最低报价记录排名, 更新数据库排名
        updateBiddingRanking(onLineBidding.getId());
        return Wrapper.success();
    }

    /**
     * 获取采购报价单内部流程状态
     */
    @Override
    public Wrapper<List<BiddingExternalWorkStateEnumResponse>> interiorStatus() {
        List<BiddingExternalWorkStateEnumResponse> collect = Arrays.stream(OnlineInteriorWorkStateEnum.values()).map(temp -> {
            BiddingExternalWorkStateEnumResponse response = new BiddingExternalWorkStateEnumResponse();
            response.setName(temp.getName());
            response.setSatatus(temp.getState());
            return response;
        }).collect(Collectors.toList());
        return Wrapper.success(collect);
    }

    /**
     * 获取采购报价单外部流程状态
     */
    @Override
    public Wrapper<List<BiddingExternalWorkStateEnumResponse>> externalStatus() {
        List<BiddingExternalWorkStateEnumResponse> collect = Arrays.stream(OnlineBiddingExternalWorkStateEnum.values()).map(temp -> {
            BiddingExternalWorkStateEnumResponse response = new BiddingExternalWorkStateEnumResponse();
            response.setName(temp.getName());
            response.setSatatus(temp.getState());
            return response;
        }).collect(Collectors.toList());
        return Wrapper.success(collect);
    }


    /**
     * 组装报价台信息
     */
    private List<QuotationDeskResponse> quotationDesks(List<OfferLogsResponse> offerLogs) {
        if (CollectionUtils.isEmpty(offerLogs)) {
            return new ArrayList<>();
        }
        return offerLogs.stream().map(temp -> {
            QuotationDeskResponse quotationDesk = new QuotationDeskResponse();
            quotationDesk.setOfferTime(temp.getOfferTime());
            quotationDesk.setPrice(temp.getOfferPrice());
            quotationDesk.setMinPrice(temp.getMinPrice());
            return quotationDesk;
        }).sorted(Comparator.comparing(QuotationDeskResponse::getOfferTime).reversed()).collect(Collectors.toList());

    }


    /**
     * 组装报价历史信息: 报价次数、报价时间、报价金额、对比前次、当前最低价、排名
     * @param response 返回封装对象
     * @param onLineBidding 在线竞价信息
     * @param memberId 登录会员id
     * @param memberRoleId 登录会员角色id
     * @param peportPriceSum 供应商当前报价次数
     */
    private List<OfferLogsResponse> offerLogs(OnlineBiddingDetailsResponse response, OnLineBidding onLineBidding, Long memberId, Long memberRoleId, Long peportPriceSum) throws JsonProcessingException {
        //查询当前供应商报价信息
        String key = memberId + "_" + memberRoleId;
        String object = redisStringUtils.hGet(PurchaseInquiryConstant.BIDDING_RANKING_LIST_DETAILS + onLineBidding.getId(), key, Constants.PURCHASE_INDEX);
        if (!StringUtils.hasLength(object)){
            new ArrayList<>();
        }
        Map<String, String> map = mapper.readValue(object, new TypeReference<Map<String, String>>() {});
        List<QueryPriceDynamicResponse> queryPrices = new ArrayList<>();
        for (String next : map.keySet()) {
            String str = map.get(next);
            QueryPriceDynamicResponse dynamicResponse = mapper.readValue(str, new TypeReference<QueryPriceDynamicResponse>() {});
            queryPrices.add(dynamicResponse);
        }

        //按照报价金额排序
        long ranking = 1;
        List<OfferLogsResponse> list = queryPrices.stream().map(queryPrice ->{
            OfferLogsResponse logsResponse = new OfferLogsResponse();
            logsResponse.setOfferCount(queryPrice.getCount());
            logsResponse.setOfferTime(queryPrice.getQueryPriceTime());
            logsResponse.setOfferPrice(queryPrice.getSumPrice());
            logsResponse.setOfferRatio(queryPrice.getOfferRatio());
            logsResponse.setRanking(queryPrice.getRanking());
            logsResponse.setMinPrice(queryPrice.getMinPrice());
            return logsResponse;
        }).sorted(Comparator.comparing(OfferLogsResponse::getOfferCount).reversed()).collect(Collectors.toList());
        response.setOfferLogs(list);
        //最新一次报价记录
        String str = map.get(String.valueOf(peportPriceSum));
        if (org.apache.commons.lang3.StringUtils.isNotBlank(str)){
            QueryPriceDynamicResponse queryPrice = mapper.readValue(str, new TypeReference<QueryPriceDynamicResponse>() {});
            response.setOfferCount(queryPrice.getCount());
            response.setOfferPrice(queryPrice.getSumPrice());
            response.setOfferRatio(queryPrice.getOfferRatio());
            response.setRanking(queryPrice.getRanking());
            response.setMinLowPrice(queryPrice.getMinPrice());
        }
        return list;
    }

    /**
     * 2、点击报价，先判断当前报价次数是否小于允许报价次数，
     * 小于则在竞价物料表格栏中插入一笔新的报价记录，
     * 大于或等于则提示：“当前报价次数已超过允许报价次数！”，
     * 3、新增报价记录中，置当前报价次数+1，
     * 单价(含税)为空，点击可以填写税率(数字格式，最多保留2位小数，可为0，为0时表示免税)，
     * 点击可以填写单价(含税)（货币型，最高保留3位小数），
     * 含税金额（货币型，最高保留2位小数）=单价(含税)*采购数量，报价金额(含税)=含税金额累计
     * 3、点击提交报价，将当前报价提交，
     * 提交时要判断报价金额(含税)-当前最低价是否大于或等于最小价差，
     * 是则允许提交，否则提示：“当前报价金额-当前最低价小于最小价差，
     * 请修改后再报价！”，提交后置报价时间=提交时间，提交后不允许再修改单价(含税)。
     */
    private Wrapper<Void> isReportPrice(Bidding bidding, OnLineBidding onLineBidding, Double sumPricie, Double minPrice, Long peportPriceSum) {
        //判断是否超过竞价时间
        if (System.currentTimeMillis() >= bidding.getBiddingEndTime()) {
            return Wrapper.fail(ResponseCode.EXCEED_END_SIGNUP_TIME);
        }
        //报价需要大于0
        if (sumPricie <= 0) {
            return Wrapper.fail(ResponseCode.BIDDING_PRICE_LT_ZERO);
        }
        //先判断当前报价次数是否小于允许报价次数
        if (bidding.getAllowPurchaseCount() < peportPriceSum) {
            return Wrapper.fail(ResponseCode.EXCEED_REPORT_COUNT);
        }
        //判断报价是否低于起拍价
        if (OrderConstant.State.START.equals(bidding.getIsStartingPrice()) && sumPricie > bidding.getStartingPrice()) {
            return Wrapper.fail(ResponseCode.REPORT_PERICE_ERROR_GOE_MAXPRICE);
        }
        double minDifference = bidding.getMinPrice().compareTo(0D) == 0 ? 1 : bidding.getMinPrice();
        //提交时要判断报价金额(含税)-当前最低价是否大于或等于最小价差，
        if ((0 != onLineBidding.getCount() && minDifference > (minPrice - sumPricie))) {
            return Wrapper.fail(ResponseCode.REPORT_PERICE_ERROR);
        }
        return Wrapper.success();
    }

    /**
     * 初始化报价物料信息
     */
    private void initOnlineMateriels(OnlineMateriel onlineMateriel, List<OnlineProductRequest> requests, OnLineBidding onLineBidding, Double minPrice) {
        //初始化当前报价物料
        List<OnLineBiddingProduct> productList = requests.stream().map(request -> {
            OnLineBiddingProduct onLineBiddingProduct = BeanUtil.copyProperties(request, OnLineBiddingProduct.class);
            onLineBiddingProduct.setBiddingNo(onLineBidding.getBiddingNo());
            onLineBiddingProduct.setReportNumber(onlineMateriel.getPeportPriceSum());
            onLineBiddingProduct.setOnlineMateriel(onlineMateriel);
            onLineBiddingProduct.setReportTime(System.currentTimeMillis());
            onLineBiddingProduct.setMinPrice(minPrice);
            return onLineBiddingProduct;
        }).collect(Collectors.toList());
        onLineBiddingProductRepository.saveAll(productList);
        //提交下事务, 需要后续查询出来
        onLineBiddingProductRepository.flush();
    }

    /**
     * 更新当前数据库报价排名
     */
    public void updateBiddingRanking(Long onLineBiddingId) {
        //事务提交后,计算当前竞价单所有供应商最低报价排名
        //当前排名
        long ranking = 1;
        //获取当前竞价单所有竞价过的供应商
        List<OnlineMateriel> materiels = onlineMaterielRepository.findAllByOnlineBiddingIdAndIsOffer(onLineBiddingId, StatusEnum.YES.getState());
        //redis竞价排名信息
        List<Map<String, Double>> scoreList = redisStringUtils.rangeWithScoresOrderByScore(PurchaseInquiryConstant.BIDDING_RANKING_LIST_KEY + onLineBiddingId, 0, materiels.size());
        for (Map<String, Double> map : scoreList) {
            for (String s : map.keySet()) {
                //获取对应供应商最低价排名 ,存入数据库
                String[] memberData = s.split("_");
                OnlineMateriel materiel = materiels.stream().filter(temp -> Long.valueOf(memberData[0]).equals(temp.getCreateMemberId()) && Long.valueOf(memberData[1]).equals(temp.getCreateMemberRoleId())).findFirst().orElse(null);
                if (Objects.isNull(materiel)) {
                    return;
                }
                //最后一次报价信息
                List<OnLineBiddingProduct> products = onLineBiddingProductRepository.findAllByOnlineMaterielAndReportNumber(materiel, materiel.getPeportPriceSum());
                if (CollectionUtils.isEmpty(products)) {
                    return;
                }
                long finalRanking = ranking;
                products.forEach(temp -> temp.setRanking(finalRanking));
                onLineBiddingProductRepository.saveAll(products);
                onLineBiddingProductRepository.flush();
                ranking++;
            }
        }
    }

    /**
     * 更新报价排名
     */
    public void updateRanking(OnLineBidding onLineBidding, OnlineMateriel onlineMateriel, Double sumPricie, Double minPrice, String company) {
        //报价会员信息
        Long memberId = onlineMateriel.getCreateMemberId();
        Long memberRoleId = onlineMateriel.getCreateMemberRoleId();
        QueryPriceDynamicResponse queryPrice = new QueryPriceDynamicResponse();
        queryPrice.setId(onLineBidding.getId());
        queryPrice.setMemberId(memberId);
        queryPrice.setMemberRoleId(memberRoleId);
        queryPrice.setMemberName(onlineMateriel.getCreateMemberName());
        queryPrice.setCount(onlineMateriel.getPeportPriceSum());
        queryPrice.setQueryPriceTime(System.currentTimeMillis());
        queryPrice.setSumPrice(sumPricie);
        queryPrice.setContacts(onlineMateriel.getContacts());
        try {
            //和上一次报价比例 (本次报价金额-上次报价金额)/上次报价金额*100%
            double offerRatio;
            String key = memberId + "_" + memberRoleId;
            queryPrice.setMinPrice(minPrice);
            queryPrice.setOfferRatio(1D);
            //查询上一次报价总额
            Double score = redisStringUtils.score(PurchaseInquiryConstant.BIDDING_RANKING_LIST_KEY + onLineBidding.getId(), key);
            //判断是否是第一次报价
            boolean flag = StatusEnum.NO.getState().equals(onlineMateriel.getIsOffer());
            if (flag){
                offerRatio = score != null && score > 0 ?  BigDecimal.valueOf((sumPricie - score)/score).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0;
                queryPrice.setOfferRatio(offerRatio);
                //第一次报价 新增redis排名
                redisStringUtils.addZSet(PurchaseInquiryConstant.BIDDING_RANKING_LIST_KEY + onLineBidding.getId(), key, sumPricie);
            }
            //如果同一个供应商当前报价低于上一次报价, 则覆盖上一次报价总额
            if (score != null && sumPricie.compareTo(score) < 0) {
                redisStringUtils.addZSet(PurchaseInquiryConstant.BIDDING_RANKING_LIST_KEY + onLineBidding.getId(), key, sumPricie);
            }
            //同时更新当前最低价信息
            setCountToRedis(sumPricie, onLineBidding, company, flag);
            //查询当前排名
            Long zSet = redisStringUtils.findZSet(PurchaseInquiryConstant.BIDDING_RANKING_LIST_KEY + onLineBidding.getId(), key);
            queryPrice.setRanking(zSet + 1);
            //缓存供应商报价信息
            String json = mapper.writeValueAsString(queryPrice);
            //查询当前供应商报价信息
            Map<String, String> map = new HashMap<>();
            String object = redisStringUtils.hGet(PurchaseInquiryConstant.BIDDING_RANKING_LIST_DETAILS + onLineBidding.getId(), key, Constants.PURCHASE_INDEX);
            if (StringUtils.hasLength(object)){
                map = mapper.readValue(object, new TypeReference<Map<String, String>>() {});
            }
            map.put(onlineMateriel.getPeportPriceSum() +"", json);
            redisStringUtils.hSet(PurchaseInquiryConstant.BIDDING_RANKING_LIST_DETAILS + onLineBidding.getId(), key, JSONUtil.toJsonStr(map),Constants.PURCHASE_INDEX);
        } catch (JsonProcessingException e) {
            log.error("采购竞价报价转json异常", e);
        }
    }


    /**
     * 更新缓存竞价单总报价次数、最低报价金额、报价会员信息
     */
    private void setCountToRedis(Double minPrice, OnLineBidding onLineBidding, String memberName, boolean flag) {
        //第一次报价 直接更新缓存
        Map<String, String> map = new HashMap<>();
        if (flag){
            map.put(PurchaseInquiryConstant.BiddingDynamic.MIN_PRICE, minPrice + "");
            map.put(PurchaseInquiryConstant.BiddingDynamic.MEMBER_NAME, memberName);
            redisStringUtils.hMSet(PurchaseInquiryConstant.BIDDING_RANKING_COUNT_KEY + onLineBidding.getId(), map, Constants.PURCHASE_INDEX);
            redisStringUtils.hIncrement(PurchaseInquiryConstant.BIDDING_RANKING_COUNT_KEY + onLineBidding.getId(), PurchaseInquiryConstant.BiddingDynamic.COUNT, Constants.PURCHASE_INDEX);
        }else {
            //判断是否低于当前最低价
            Map<String, String> ranking = redisStringUtils.hGetAll(PurchaseInquiryConstant.BIDDING_RANKING_COUNT_KEY + onLineBidding.getId(), Constants.PURCHASE_INDEX);
            Double redisMinPrice = Double.valueOf(StringUtils.hasLength(ranking.get(PurchaseInquiryConstant.BiddingDynamic.MIN_PRICE)) ? ranking.get(PurchaseInquiryConstant.BiddingDynamic.MIN_PRICE) : "0");
            if (minPrice.compareTo(redisMinPrice) < 0) {
                map.put(PurchaseInquiryConstant.BiddingDynamic.MIN_PRICE, minPrice + "");
                map.put(PurchaseInquiryConstant.BiddingDynamic.MEMBER_NAME, memberName);
                redisStringUtils.hMSet(PurchaseInquiryConstant.BIDDING_RANKING_COUNT_KEY + onLineBidding.getId(), map, Constants.PURCHASE_INDEX);
                redisStringUtils.hIncrement(PurchaseInquiryConstant.BIDDING_RANKING_COUNT_KEY + onLineBidding.getId(), PurchaseInquiryConstant.BiddingDynamic.COUNT, Constants.PURCHASE_INDEX);
            }
        }
    }

    /**
     * 查询采购竞价报价单内部操作记录
     */
    public List<BiddingInteriorLogResponse> getOnlineInteriorLog(Long onlineBiddingId) {
        List<OnlineInteriorLog> onlineInteriorLogs = onlineInteriorLogRepository.findAllByOnlineBiddingId(onlineBiddingId);
        if (CollectionUtils.isEmpty(onlineInteriorLogs)) {
            return new ArrayList<>();
        }
        return onlineInteriorLogs.stream().map(temp -> BeanUtil.copyProperties(temp, BiddingInteriorLogResponse.class)).collect(Collectors.toList());
    }


    /**
     * 组装采购单会员报名信息
     */
    private void assemblyData(OnlineSignUpRequest request, OnlineMateriel onlineMateriel) {
        //生成报价单
        BeanUtil.copyProperties(request, onlineMateriel);
        List<CountryAreaResponse> areas = request.getAreas();
        onlineMateriel.setAddress(request.getAddress());
        onlineMateriel.setSignUpAreas(BeanUtil.copyProperties(request.getSignUpAreas(), CountryArea.class));
        onlineMateriel.setAreas(areas.stream().map(area -> BeanUtil.copyProperties(area, CountryArea.class)).collect(Collectors.toList()));
        onlineMateriel.setSignUpTime(System.currentTimeMillis());
    }

    /**
     * 记录内部操作记录
     */
    public void initOnlineInteriorLog(UserLoginCacheDTO sysUser, Integer oetation, Integer state, Long onlineBiddingId, String discardCaues) {
        OnlineInteriorLog interiorLog = new OnlineInteriorLog();
        interiorLog.setOperation(oetation);
        interiorLog.setCreateTime(System.currentTimeMillis());
        interiorLog.setState(state);
        interiorLog.setRoleName(sysUser.getMemberRoleName());
        interiorLog.setPosition(sysUser.getUserJobTitle());
        interiorLog.setCreateMemberId(sysUser.getMemberId());
        interiorLog.setMemberRoleId(sysUser.getMemberRoleId());
        interiorLog.setMemberId(sysUser.getMemberId());
        interiorLog.setDepartment(sysUser.getUserOrgName());
        interiorLog.setOnlineBiddingId(onlineBiddingId);
        interiorLog.setAuditOpinion(discardCaues);
        onlineInteriorLogRepository.saveAndFlush(interiorLog);
    }

    private Double getMinPrice(OnLineBidding onLineBidding, Double sumPricie) {
//        if (!OrderConstant.State.START.equals(bidding.getIsStartingPrice())) {
//            return 0.0;
//        }
        String minPriceStr = redisStringUtils.hMGet(PurchaseInquiryConstant.BIDDING_RANKING_COUNT_KEY + onLineBidding.getId(), PurchaseInquiryConstant.BiddingDynamic.MIN_PRICE, Constants.PURCHASE_INDEX);
        double minPrice;
        if (!StringUtils.hasLength(minPriceStr) || Double.valueOf(minPriceStr).compareTo(0D) == 0) {
            //当前报价
            return sumPricie;
        } else {
            minPrice = Double.parseDouble(minPriceStr);
        }
        return minPrice;
    }

    /**
     * 异步发送数据给前端
     */
    public void sendWebSocket(Bidding bidding) {
        executor.execute(() -> {
            WebSocketBiddingResponse webSocketBidding = new WebSocketBiddingResponse();
            OnLineBidding onLineBidding = onlineBiddingRepository.findFirstByBiddingId(bidding.getId());
            List<OnlineMateriel> materiels = onlineMaterielRepository.findAllByOnlineBiddingIdAndIsSignUp(onLineBidding.getId(), StatusEnum.YES.getState());
            if (CollectionUtils.isEmpty(materiels)) {
                return;
            }
            //报价会员信息
            List<SginUpInfoResponse> sginUpInfoResponses = materiels.stream().filter(temp ->StatusEnum.YES.getState().equals(temp.getIsOffer())).map(materiel -> BeanUtil.copyProperties(materiel, SginUpInfoResponse.class)).collect(Collectors.toList());
            webSocketBidding.setSginUpInfos(sginUpInfoResponses);
            //竞价过程 物料信息
            List<AwardProcessResponse> awardProcess = getAwardProcess(bidding.getId());
            //排序：正序
            if(CollectionUtil.isNotEmpty(awardProcess)){
                awardProcess = awardProcess.stream().sorted(Comparator.comparing(AwardProcessResponse::getSumPice)).collect(Collectors.toList());
            }
            webSocketBidding.setAwardProcesss(awardProcess);
            //报价台
            List<PurcQuotationDeskResponse> deskResponses = awardProcess.stream().map(awardProcessResponse -> {
                PurcQuotationDeskResponse response = new PurcQuotationDeskResponse();
                response.setMinPrice(awardProcessResponse.getSumPice());
                response.setPeportTime(awardProcessResponse.getPeportTime());
                return response;
            }).collect(Collectors.toList());
            webSocketBidding.setDeskResponses(deskResponses);
            //报价排名
            try {
                BaseDetailsRequest request = new BaseDetailsRequest();
                request.setId(bidding.getId());
                webSocketBidding.setQueryPriceDynamics(rankingBidding(request));
            } catch (BusinessException e) {
                log.error("获取报价排名失败, 异常信息: 竞价排名JSON解析异常");
                return;
            }
            //竞价动态 - 报价总次数和最新排名用户信息
            Map<String, String> map = redisStringUtils.hGetAll(PurchaseInquiryConstant.BIDDING_RANKING_COUNT_KEY + onLineBidding.getId(), Constants.PURCHASE_INDEX);
            webSocketBidding.setId(bidding.getId());
            webSocketBidding.setCount(Long.valueOf(null == map.get(PurchaseInquiryConstant.BiddingDynamic.COUNT) ? "0" : map.get(PurchaseInquiryConstant.BiddingDynamic.COUNT)));
            webSocketBidding.setMemberName(map.get(PurchaseInquiryConstant.BiddingDynamic.MEMBER_NAME));
            webSocketBidding.setMinPrice(Double.valueOf(StringUtils.hasLength(map.get(PurchaseInquiryConstant.BiddingDynamic.MIN_PRICE)) ? map.get(PurchaseInquiryConstant.BiddingDynamic.MIN_PRICE) : "0"));
            //供应商的消息
            List<WsMessageRequest> wsMessageRequests = sendWebSocketSupplier(onLineBidding, materiels);
            //采购商消息
            WsMessageRequest wsMessageRequest = new WsMessageRequest();
            wsMessageRequest.setMemberId(bidding.getCreateMemberId());
            wsMessageRequest.setRoleId(bidding.getCreateMemberRoleId());
            wsMessageRequest.setAction(WsAction.PURCHASE_BIDDING_MESSAGE);
            wsMessageRequest.setData(webSocketBidding);
            wsMessageRequests.add(wsMessageRequest);
            wsMessageControllerFeign.batchSendWsMessage(wsMessageRequests);
        });
    }

    /**
     * 组装供应商在线竞价- 实时竞价台信息
     * @param onLineBidding
     * @param materiels
     * @return
     */
    private List<WsMessageRequest> sendWebSocketSupplier(OnLineBidding onLineBidding, List<OnlineMateriel> materiels) {
        List<WsMessageRequest> wsMessages = new ArrayList<>();
        materiels.forEach(temp -> {
            //发送给供应商
            WebSocketBiddingSupplierResponse webSocketBidding = new WebSocketBiddingSupplierResponse();
            //报价台和历史报价信息
            try {
                assembleWebSocketQueryPrice(webSocketBidding, onLineBidding, temp);
            } catch (JsonProcessingException e) {
                log.error("获取供应商在线报价 实时竞价信息异常, 异常信息:{}", e.getMessage());
                return;
            }
            WsMessageRequest wsMessageRequest = new WsMessageRequest();
            wsMessageRequest.setMemberId(temp.getCreateMemberId());
            wsMessageRequest.setRoleId(temp.getCreateMemberRoleId());
            wsMessageRequest.setAction(WsAction.PURCHASE_BIDDING_MESSAGE_SUPPLIER);
            wsMessageRequest.setData(webSocketBidding);
            wsMessages.add(wsMessageRequest);
        });
        return wsMessages;
    }
}
